#ifndef XG_HTTPCODER_H
#define XG_HTTPCODER_H
//////////////////////////////////////////////////////////
#include "HttpBase.h"

#ifndef HTTP2_FRAME_MAXSIZE
#define HTTP2_FRAME_MAXSIZE		(1 << 14)
#endif

#ifndef HTTP2_STRING_MAXLEN
#define HTTP2_STRING_MAXLEN		(4 * 1024)
#endif

#ifndef HTTP2_WINDOW_MAXSIZE
#define HTTP2_WINDOW_MAXSIZE	(1024 * 1024 * 1024)
#endif

#define HTTP2_HEAD_SIZE			9

#define HTTP2_PROTOCOL_ERROR 	1
#define HTTP2_INTERNAL_ERROR 	2
#define HTTP2_REFUSED_STREAM	7


#define HTTP2_ACK_FLAG	  		0x01
#define HTTP2_END_STREAM		0x01
#define HTTP2_END_HEADER		0x04
#define HTTP2_HAS_PADDING		0x08
#define HTTP2_HAS_PRIORITY		0x20

#define HTTP2_DATA_FRAME			0
#define HTTP2_HEADER_FRAME			1
#define HTTP2_PRIORITY_FRAME		2
#define HTTP2_RSTSTREAM_FRAME		3
#define HTTP2_SETTINGS_FRAME		4
#define HTTP2_PUSHPROMISE_FRAME		5
#define HTTP2_PING_FRAME			6
#define HTTP2_GOAWAY_FRAME			7
#define HTTP2_WINDOWUPDATE_FRAME	8
#define HTTP2_CONTINUATION_FRAME	9

#pragma pack(1)

struct HttpFrameData
{
	char sz[3];
	u_char type;
	u_char flag;
	u_int32 seqno;
	u_char data[1];

	u_int32 getId() const
	{
		u_int32 id = ntohl(seqno);
		BIT_SET(id, 31, 0);
		return id;
	}
	void setId(u_int32 id)
	{
		seqno = htonl(id);
	}
	u_int32 getSize() const
	{
		u_char arr[] = { 0, 0, 0, 0 };
		memcpy(arr + 1, sz, 3);
		return ntohl(*(u_int32*)(arr));
	}
	void setSize(u_int32 sz)
	{
		sz = htonl(sz);
		memcpy(this->sz, (char*)(&sz) + 1, 3);
	}
	u_int32 getFrameSize() const
	{
		return getSize() + HTTP2_HEAD_SIZE;
	}
};

struct HttpSettingItem
{
	u_int16 key;
	u_int32 val;

	static HttpFrameData* GetAckFrame();
	static HttpFrameData* GetGoawayFrame();
	static HttpFrameData* GetCommonFrame(bool updated = false);
};

#pragma pack()

class HttpHeadItem : public Object
{
public:
	string key;
	string val;

	string toString() const
	{
		return key.empty() ? stdx::EmptyString() : key + ": " + val + "\r\n";
	}
	HttpHeadItem(const string& key = "", const string& val = "")
	{
		this->key = key;
		this->val = val;
	}
};

class HttpHeadVector : public Object
{
protected:
	int maxsz;
	vector<HttpHeadItem> vec;

public:
	const HttpHeadItem& get(int idx) const;
	u_char index(const string& key, const string& val) const;

public:
	HttpHeadVector() : maxsz(63)
	{
	}

public:
	void clear()
	{
		maxsz = 63;
		vec.clear();
	}
	int size(int sz = -1)
	{
		if (sz >= 0)
		{
			maxsz = min(sz, 63);
			while (maxsz < vec.size()) vec.pop_back();
		}

		return vec.size();
	}
	void push(const HttpHeadItem& item)
	{
		vec.insert(vec.begin(), item);
		while (maxsz < vec.size()) vec.pop_back();
	}
};

class HttpCoder : public Object
{
public:
	static int EncodeInteger(void* dest, int val, int fix = 7);
	static int DecodeInteger(const void* src, int& sz, int fix = 7);
	static int GetString(const char* str, const char* end, string& val);
	static int DecodeHuff(const void* src, int len, void* dest, u_char* state = NULL);
};

//////////////////////////////////////////////////////////
#endif